package com.hw.nio.netty.websocket;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.Buffer;
import java.nio.ByteBuffer;

public class WebSocketServer {


    private ByteBuf indexPage;
    private ChannelGroup channelGroup;


    {
        try {
            initStaticPage();
        } catch (URISyntaxException | IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException, IOException {
        WebSocketServer webSocketServer = new WebSocketServer();
        webSocketServer.openServer(8888);
        System.in.read();

    }

    public void openServer(int port) throws InterruptedException {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(new NioEventLoopGroup(1));

        bootstrap.channel(NioServerSocketChannel.class);
        ChannelFuture sync = bootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                ch.pipeline().addLast("decode", new HttpRequestDecoder());
                ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
                ch.pipeline().addLast("encode", new HttpResponseEncoder());
                ch.pipeline().addLast("http-servlet", new MyHttpServlet());
                ch.pipeline().addLast("ws-codec", new WebSocketServerProtocolHandler("/ws"));
                ch.pipeline().addLast("ws-servlet", new MyWsServlet());
            }
        })
                .bind(port)
                .sync();


        channelGroup = new DefaultChannelGroup(sync.channel().eventLoop());
        System.out.println("服务开启成功");
    }


    // 读取html文件
    public void initStaticPage() throws URISyntaxException, IOException {
        URL location = WebSocketServer.class.getProtectionDomain().getCodeSource().getLocation();
        String path = location.toURI() + "WebsocketDanMu.html";
        path = !path.contains("file:") ? path : path.substring(5);

        RandomAccessFile file = new RandomAccessFile(path, "r");
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
        file.getChannel().read(byteBuffer);
        byteBuffer.flip();
        indexPage = Unpooled.wrappedBuffer(byteBuffer);
        file.close();
    }

    private class MyHttpServlet extends SimpleChannelInboundHandler<FullHttpRequest> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
            if (msg.uri().equals("/")) {
                DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
                response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
                response.headers().set(HttpHeaderNames.CONTENT_LENGTH, indexPage.capacity());
                response.content().writeBytes(indexPage.duplicate());
                ctx.writeAndFlush(response);
            } else if (msg.uri().equals("/ws")) {
                ctx.fireChannelRead(msg.retain());
            }
        }
    }

    private class MyWsServlet extends SimpleChannelInboundHandler<TextWebSocketFrame> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
            System.out.println(msg.text());
            channelGroup.add(ctx.channel());
            channelGroup.writeAndFlush(new TextWebSocketFrame(msg.text()));
        }
    }
}
